using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Reflection;
using log4net;
using log4net.Appender;
using log4net.Config;
using log4net.Layout;

namespace RL
{
    public enum ELogLevel
    {
        Debug,
        Error,
        Fatal,
        Info,
        Warn
    }

    public enum LogFile
    {
        Server,
        Client
    }

    public static class Logger
    {
        private static readonly object _logLock = new object();

        public static IAppender CreateFileAppender(string name, string fileName)
        {
            RollingFileAppender appender =
                new RollingFileAppender
                {
                    Name = name,
                    File = fileName,
                    AppendToFile = true,
                    RollingStyle = RollingFileAppender.RollingMode.Size,
                    MaxSizeRollBackups = 20,
                    MaximumFileSize = "20MB",
                    Threshold = log4net.Core.Level.All
                };

            PatternLayout layout = new PatternLayout { ConversionPattern = "%d [%t] %-5p %c [%x] - %m%n" };
            layout.ActivateOptions();

            BasicConfigurator.Configure(appender);
            appender.Layout = layout;
            appender.ActivateOptions();

            return appender;
        }

        private static readonly ILog logger;

        static Logger()
        {
            //string appName;
            //string version;
            //Assembly ozdocsAssembly = GetOzDocsAssemblies().Where(x => x.GetName().Name.Contains("OzDocs") && !x.GetName().Name.Contains("Utilities")).LastOrDefault();
            //if (ozdocsAssembly != null)
            //{
            //    appName = ozdocsAssembly.GetName().Name;
            //    version = ozdocsAssembly.GetName().Version.Major + "." + ozdocsAssembly.GetName().Version.Minor + "." + ozdocsAssembly.GetName().Version.Build;
            //}
            //else
            //{
            //    appName = "NoOzDocsAssembly";
            //    version = "0.0.0";
            //}

            logger = LogManager.GetLogger("Log4net.ServerLogger");
            ((log4net.Repository.Hierarchy.Logger)logger.Logger).AddAppender(
                //CreateFileAppender("ServerLoggerAppender", Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData)
                //+ "\\OzDocsOnline\\" + appName + "." + version + ".txt")
                CreateFileAppender("ServerLoggerAppender", Environment.CurrentDirectory + "\\Debug.txt")
                );
            ((log4net.Repository.Hierarchy.Logger)logger.Logger).Additivity = false;
        }

        /// <summary>
        /// Writes the log to a logger
        /// </summary>
        /// <param name="logLevel">The log level.</param>
        /// <param name="log">The log.</param>
        public static void WriteLog(ELogLevel logLevel, String log)
        {
            lock (_logLock)
            {
                switch (logLevel)
                {
                    case ELogLevel.Debug:
                        logger.Debug(log);
                        break;

                    case ELogLevel.Error:
                        logger.Error(log);
                        break;

                    case ELogLevel.Fatal:
                        logger.Fatal(log);
                        break;

                    case ELogLevel.Info:
                        logger.Info(log);
                        break;

                    case ELogLevel.Warn:
                        logger.Warn(log);
                        break;
                }
            }
        }

        public static void WriteDebug(String log)
        {
            lock (_logLock)
            {
                WriteLog(ELogLevel.Debug, log);
            }
        }
        public static void WriteInfo(String log)
        {
            lock (_logLock)
            {
                WriteLog(ELogLevel.Info, log);
            }
        }

        /// <summary>
        /// Writes a shorter exception log
        /// </summary>
        /// <param name="ex">The ex.</param>
        public static void WriteException(Exception ex)
        {
            WriteLog(ELogLevel.Error, ex.ToString());
        }

        //<summary>
        /// Gets all the calling assemblies.
        ///</summary>
        ///<returns>An arraylist containing all the calling assemblies</returns>
        ///<remarks>
        /// The first assembly (index=0) in the list is the currently running assembly.
        /// The last assembly is the running application
        ///</remarks>
        private static List<Assembly> GetCallingAssemblies()
        {
            List<Assembly> assemblies = new List<Assembly>();

            StackTrace stackTrace = new StackTrace(0, true);
            for (int i = 0; i < stackTrace.FrameCount; i++)
            {
                StackFrame stackFrame = stackTrace.GetFrame(i);
                MethodBase methodBase = stackFrame.GetMethod();
                Type type = methodBase.ReflectedType;

                if (type == null)
                    continue;

                Assembly assembly = Assembly.GetAssembly(type);

                if (assemblies.Contains(assembly) == false)
                    assemblies.Add(assembly);
            }
            return assemblies;
        }

        ///<summary>
        /// Gets the starting assembly.
        ///</summary>
        ///<returns>
        /// The actively running assembly.
        /// For a window app, this is the .exe running.
        /// For a web app, it is the web application.
        ///</returns>
        public static Assembly GetStartingAssembly()
        {
            List<Assembly> callingAssemblies = GetCallingAssemblies();
            //Loop backwards through results
            for (int i = callingAssemblies.Count - 1; i > -1; i--)
            {
                Assembly assembly = callingAssemblies[i];
                AssemblyName assemblyName = assembly.GetName();
                string name = assemblyName.Name;
                if (name != "System.Web")
                    return assembly;
            }
            return Assembly.GetExecutingAssembly();
        }

        /// <summary>
        /// Gets the start of a calling assembly that relates to ozdocs.
        /// </summary>
        /// <returns></returns>
        public static List<Assembly> GetOzDocsAssemblies()
        {
            return GetCallingAssemblies().Where(x => x.GetName().Name.Contains("OzDocs")).ToList();
        }
    }


}

